package com.lhy.backend.serivice.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.lhy.backend.common.exception.ServiceException;
import com.lhy.backend.common.response.HttpStatus;
import com.lhy.backend.components.utils.JwtUtils;
import com.lhy.backend.domain.dto.LoginDto;
import com.lhy.backend.domain.entity.user.*;
import com.lhy.backend.domain.vo.RouterVO;
import com.lhy.backend.mapper.user.SysMenuMapper;
import com.lhy.backend.mapper.user.SysRoleMapper;
import com.lhy.backend.mapper.user.SysRoleMenuMapper;
import com.lhy.backend.mapper.user.SysUserRoleMapper;
import com.lhy.backend.serivice.IAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class AuthServiceImpl implements IAuthService {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private  AuthenticationManager authenticationManager;


    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Override
    public String login(LoginDto loginDto) {
        try {
            //传入用户名和密码 将是否认证标记设置为false
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
            //实现的登录逻辑，此时就会调用loadUserByUsername方法
            //返回 Authentication 其实就是UserDetails
            Authentication authentication = authenticationManager.authenticate(authenticationToken);
            //获取返回的用户
            SysUser sysUser = (SysUser) authentication.getPrincipal();
            // 如果到这里没有抛出异常，说明认证成功
            if(ObjectUtils.isNull(sysUser)) {
                return "error";
            } else {
                Map<String,Object> SysUserInfoMap = new HashMap();
                SysUserInfoMap.put("id", sysUser.getId());
                SysUserInfoMap.put("username", sysUser.getUsername());
                SysUserInfoMap.put("nickname", sysUser.getNickname());
                SysUserInfoMap.put("status", sysUser.getStatus());
                SysUserInfoMap.put("avatar", sysUser.getAvatar());
                SysUserInfoMap.put("roleList", sysUser.getRoleList());
                SysUserInfoMap.put("perms", sysUser.getPerms());
                return jwtUtils.createToken(SysUserInfoMap);
            }
        } catch (AuthenticationException e) {
            return "error";
        }
    }

    @Override
    public List<RouterVO> getMenus() {
        SysUser sysUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (ObjectUtils.isNotNull(sysUser)) {
            //获取角色id
            LambdaQueryWrapper<SysUserRole> sysUserRoleWrapper = new LambdaQueryWrapper<>();
            sysUserRoleWrapper.eq(SysUserRole::getUserId, sysUser.getId());
            List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectList(sysUserRoleWrapper);
            //获取角色
            LambdaQueryWrapper<SysRole> sysRoleWrapper = new LambdaQueryWrapper<>();
            List<Long> sysRoleIds = sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
            sysRoleWrapper.in(SysRole::getRoleId, sysRoleIds);
            Set<SysRole> roleList = new HashSet<>(sysRoleMapper.selectList(sysRoleWrapper));
            sysUser.setRoleList(roleList);
            //获取menuId
            LambdaQueryWrapper<SysRoleMenu> sysRoleMenuWrapper = new LambdaQueryWrapper<>();
            sysRoleMenuWrapper.in(SysRoleMenu::getRoleId, sysRoleIds);
            List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectList(sysRoleMenuWrapper);
            List<Long> sysMenuIds = sysRoleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
            //根据角色查询权限 menu
            LambdaQueryWrapper<SysMenu> sysMenuWrapper = new LambdaQueryWrapper<>();
            sysMenuWrapper.in(SysMenu::getId, sysMenuIds);
            List<SysMenu> sysMenus = sysMenuMapper.selectList(sysMenuWrapper);
            // 通过递归设置菜单的树形结构
            // 1、获取所有的1级菜单【parentId = 0】
            // 2、遍历1级菜单，获取他所有的子元素【其他数据的parentId = 当前元素的id】
            List<RouterVO> router = getRouter(sysMenus);
            return router;
        }else{
            return null;
        }
    }
    /**
     * 获取路由
     */
    private List<RouterVO> getRouter(List<SysMenu> menuList) {
        List<RouterVO> routerVOS = new ArrayList<>();
        // 首先获取所有的1级路由
        List<SysMenu> parentMenu = menuList.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());
        // 转换对象类型
        for (SysMenu menu : parentMenu) {
            RouterVO routerVO = new RouterVO();
            BeanUtil.copyProperties(menu,routerVO);
            routerVOS.add(routerVO);
        }
        // 循环1级路由，获取所有的子菜单
        for (RouterVO routerVO : routerVOS) {
            // 获取所有的子节点
            List<RouterVO> childrenList = buildTree(menuList, routerVO.getId());
            routerVO.setChildren(childrenList);
        }
        return routerVOS;
    }

    /**
     * 获取所有子节点，递归获取【如果是2级不需要递归了】
     */
    private List<RouterVO> buildTree(List<SysMenu> allMenu, Long parentId) {
        List<RouterVO> childrenList = new ArrayList<>();
        // 遍历所有的数据
        for (SysMenu menu : allMenu) {
            // 判断menu的parentId是否与传进来的parentId相同
            if(menu.getParentId().equals(parentId)) {
                RouterVO routerVO = new RouterVO();
                BeanUtil.copyProperties(menu,routerVO);
                childrenList.add(routerVO);
            }
        }
        // 递归childrenList可能还有子节点
        for (RouterVO childrenItem : childrenList) {
            childrenItem.setChildren(buildTree(allMenu,childrenItem.getId()));
        }
        return childrenList;
    }
}




























